<?php

// @formatter:off
/**
 * @file WCERepository.php
 * @author Alejandro Dario Simi
 * @date $Date: 2014-05-04 01:33:52 +0000 (Sun, 04 May 2014) $
 *
 * $Id: WCERepository.php 111 2014-05-04 01:33:52Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/trunk/extensions/Repositories/includes/WCERepository.php $
 */
class WCERepository {
	/**
	 * @var WCERepository[string][int] Pointer to the singleton instance.
	 */
	protected static $_Instance = array();
	/**
	 * @var boolean[string] This is a list of flags used to avoid repeating heavy
	 * operations.
	 */
	protected $_flags = array(
		"checkBalance" => false,
		"loadDirectories" => false
	);
	/**
	 * @var WCConnection Pointer to the global connection object.
	 */
	protected $_db = false;
	/**
	 * @var string Shortcut to database tables prefixes.
	 */
	protected $_dbprefix = "";
	/**
	 * @var WCDirectory Main directory pointer.
	 */
	protected $_mainDirectory = false;
	/**
	 * @var WCGContainer This container holds all repositories.
	 */
	protected $_directories = false;
	/**
	 * @var WCDirectory Unbalanced directory pointer.
	 */
	protected $_badDirectory = false;
	/**
	 * @var int Amount of items required to correct an unbalanced directory.
	 */
	protected $_correctionSize = false;
	/**
	 * @var WCGroup Current group.
	 */
	protected $_group = false;
	/**
	 * @var boolean Indicates if main directory exists but it somehow broken.
	 */
	protected $_broken = false;
	/**
	 * @var boolean Indicates if all directories are balanced.
	 */
	protected $_balanced = false;
	/**
	 * @var string This is the directory name to use when all repository's
	 * buckets are full and it's unbalanced.
	 */
	protected $_nextName = false;
	/**
	 * Constructor is protected because it's a singleton.
	 */
	protected function __construct(WCGroup &$group) {
		//
		// Loading global pointers.
		global $wcDatabaseAccess;
		//
		// Loading shortcuts.
		// @{
		$this->_db = WCConnection::Instance();
		$this->_dbprefix = $wcDatabaseAccess["prefix"];
		$this->_group = $group;
		// @}
		//
		// Creating a list for sub-directories.
		$this->_directories = new WCContainer(WCDirectoriesHolder::I());
	}
	/**
	 * Prevent users to clone the instance.
	 */
	public function __clone() {
		trigger_error(__CLASS__.": Clone is not allowed.", E_USER_ERROR);
	}
	//
	// Public methods.
	/**
	 * @return WCDirectory
	 */
	public function badDirectory() {
		return $this->_badDirectory;
	}
	/**
	 * @return boolean
	 */
	public function balanced() {
		$this->checkBalance();
		return $this->_balanced;
	}
	/**
	 * @return WCDirectory
	 */
	public function balancer() {
		trigger_error(__CLASS__."::".__FUNCTION__.": Subclass responsibility.", E_USER_ERROR);
		return false;
	}
	/**
	 * @return boolean
	 */
	public function broken() {
		$this->loadDirectories();
		return $this->_broken;
	}
	public function correctionSize() {
		return $this->_correctionSize;
	}
	public function createBalancer() {
		$out = false;

		if(!$this->broken() && !$this->balanced() && !$this->balancer()) {
			global $wcDefaults;

			$path = WCSanitizer::SystemPath($this->_group->root().$this->_nextName);
			if(!is_dir($path)) {
				//
				// Physically creating the directory.
				mkdir($path, $wcDefaults["directory-permissions"], true);
			}
			$directory = WCDirectoriesHolder::I()->createInGroup($this->_nextName, $this->_group);
			WCDirectoriesHolder::I()->resetCache();

			$this->reload();

			$out = true;
		}

		return $out;
	}
	/**
	 * @return WCDirectory[]
	 */
	public function directories() {
		$this->loadDirectories();
		return $this->_directories->items();
	}
	/**
	 * @return WCGroup
	 */
	public function group() {
		return $this->_group;
	}
	/**
	 * @return WCDirectory
	 */
	public function mainDirectory() {
		$this->loadDirectories();
		return $this->_mainDirectory;
	}
	public function reload() {
		if(!$this->broken()) {
			$this->_mainDirectory->reload();
			foreach($this->directories() as $dir) {
				$dir->reload();
			}

			foreach($this->_flags as $key => $value) {
				$this->_flags[$key] = false;
			}
		}
	}
	//
	// Protected methods.
	protected function checkBalance() {
		trigger_error(__CLASS__."::".__FUNCTION__.": Subclass responsibility.", E_USER_ERROR);
	}
	protected function loadDirectories($first = true) {
		if(!$this->_flags["loadDirectories"]) {
			$this->_broken = false;
			$this->_flags["loadDirectories"] = true;

			$this->_mainDirectory = false;
			foreach(WCDirectoriesHolder::I()->idsByName(WC_E_REPOSITORIES_MAINDIR) as $id) {
				$item = WCDirectoriesHolder::I()->item($id);
				if($item && $item->ok() && $item->group == $this->_group->id) {
					$this->_mainDirectory = $item;
					break;
				}
			}

			if($this->_mainDirectory) {
				if($this->_mainDirectory->ok()) {
					$keep = true;
					$i = 1;
					while($keep) {
						$j = $i < 10 ? "0{$i}" : $i;
						$path = WC_E_REPOSITORIES_MAINDIR."/{$j}";
						$this->_nextName = $path;

						$srepo = false;
						foreach(WCDirectoriesHolder::I()->idsByName($path) as $id) {
							$item = WCDirectoriesHolder::I()->item($id);
							if($item && $item->ok() && $item->group == $this->_group->id) {
								$srepo = $item;
								break;
							}
						}

						if($srepo && $srepo->ok()) {
							$this->_directories->addId($srepo->id);
						} else {
							$keep = false;
						}
						$i++;
					}
				} else {
					$this->_broken = true;
					$this->_mainDirectory = false;
				}
			} elseif(!$first) {
				$this->_broken = true;
				$this->_mainDirectory = false;
			} else {
				global $wcDefaults;

				$path = WCSanitizer::SystemPath($this->_group->root().WC_E_REPOSITORIES_MAINDIR);
				if(!is_dir($path)) {
					//
					// Physically creating the directory.
					mkdir($path, $wcDefaults["directory-permissions"], true);
				}
				$directory = WCDirectoriesHolder::I()->createInGroup(WC_E_REPOSITORIES_MAINDIR, $this->_group);
				WCDirectoriesHolder::I()->resetCache();

				$this->_flags["loadDirectories"] = false;
				$this->_mainDirectory = false;
				$this->loadDirectories(false);
			}
		}
	}
}
